A computer operates under the control of programs consisting of coded instructions called object code that execute on the computer. But, object code is not readily understood by humans, so a human programmer typically writes programs in a high-level programming language, such as BASIC, PASCAL, C, C++, or the like, which is easier to understand. High-level languages generally have a precise syntax that defines certain permitted structures for statements in the language and their meaning. A compiler, which is itself a program, translates the high-level language statements, called “source code” into object code. Thus, the terms “source code” and “object code” describe the form of a program prior to and after translation, respectively. Accordingly, the term “source code” generally refers to a program in its high-level programming language form. “Object code,” on the other hand, generally refers to the program in the form of the coded instructions generated by the compiler that are executable on a computer.
In modern microprocessors, compilers play a significant role in obtaining good performance of the object code. In particular, the compiler's ability to extract instruction-level parallelism (ILP) in a program quite often holds the key to improved performance. For memory references, ILP can effectively hide the latency of performance-critical load operations by executing the loads before earlier store operations.
Without accurate data-dependence information, the efficiency of ILP to reorder memory operations suffers significantly. This accuracy of data-dependence information critically depends on the compiler's ability to distinguish memory accesses to different locations, a process called memory disambiguation. When two memory accesses cannot be disambiguated, they may be “aliased”, i.e., they may refer to the same memory location.
In many programming languages, programs can be written to dynamically allocate and create multi-dimensional arrays. Here “dynamic allocation” refers to obtaining storage at runtime as opposed to determining storage at compile time. In C programs, for example, multi-dimensional arrays are allocated and formed dynamically through the function-call “malloc” defined in the C language. The program then performs various computations on these arrays and finally deallocates them using another C language defined function-call “free”. In such programs, the compiler must disambiguate between references to dynamically-allocated multi-dimensional arrays in order to improve instruction-level parallelism. But, current techniques are inadequate to disambiguate between references to a dynamically-allocated multi-dimensional array. Therefore, performance of such programs can be severely affected when key loops cannot be parallelized due to false data dependencies that cannot be eliminated since the compiler was unable to disambiguate the dynamic-array accesses.
What is needed is a mechanism to disambiguate real data dependencies from false data dependencies, so that more loops can take advantage of instruction-level parallelism and performance of the resulting object code can be increased.